/*
 * Copyright (c) 2018 Hitevision
 */

package tw.com.hitevision.whiteboard.android.render;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;

import androidx.annotation.ColorInt;

import tw.com.hitevision.whiteboard.android.stateFile.BaseStateFile;
import tw.com.hitevision.whiteboard.android.util.IdGenerator;

public abstract class BaseItem implements Renderable {
    private final Region region;
    private final RectF rectF;
    private final Rect rect;
    private final long id;
    private volatile boolean isSelected;
    float x;
    float y;
    float width;
    float height;
    private int color;
    private boolean lock;
    private float degree;
    BaseItem() {
        id = IdGenerator.createId();
        region = new Region();
        rectF = new RectF();
        rect = new Rect();
    }
    public void setSelected(boolean selected) {
        isSelected = selected;
    }
    public boolean isSelected() {
        return isSelected;
    }
    public void setColor(@ColorInt int color) {
        this.color = color;
    }
    @ColorInt
    public int getColor() {
        return color;
    }
    public float getX() {
        return x;
    }
    public float getY() {
        return y;
    }
    /** Sets the position of the actor's bottom left corner. */
    public void setPosition(float x, float y) {
        this.x = x;
        this.y = y;
        updateRegion();
        onBoundsChanged();
    }
    /** Add x and y to current position */
    public void moveBy(float dx, float dy) {
        this.x += dx;
        this.y += dy;
        updateRegion();
        onBoundsChanged();
    }
    public float getWidth() {
        return width;
    }
    public float getHeight() {
        return height;
    }
    public void setSize(float width, float height) {
        this.width = width;
        this.height = height;
        updateRegion();
        onBoundsChanged();
    }
    /** Set bounds the x, y, width, and height. */
    public void setBounds(float x, float y, float width, float height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        updateRegion();
        onBoundsChanged();
    }
    void updateRegion() {
        rectF.set(x, y, x + width, y + height);
        rectF.roundOut(rect);
        region.set(rect);
    }
    /**
     * This method is invoked after bounds have changed.
     */
    void onBoundsChanged() {
        // do nothing
    }
    public void getRegion(Region out) {
        out.set(region);
    }
    public float getLeft() {
        return getX();
    }
    public float getRight() {
        return getX() + getWidth();
    }
    public float getTop() {
        return getY();
    }
    public float getBottom() {
        return getY() + getHeight();
    }
    public RectF getRectF() {
        return rectF;
    }
    public abstract void scaleFromPoint(float rateX, float rateY, PointF p);
//    public abstract void rotateFromPoint(float degree, PointF p);

    public void rotateFromPoint(float degree, PointF p) {
        this.degree += degree;
        this.degree %= 360;
    }
    public boolean hit(float x, float y) {
        return region.contains((int) x, (int) y);
    }
    /**
     * Returns the id of this item.
     */
    public long getId() {
        return id;
    }
    /**
     * Cleans up any resources used.  This object should not be touched after {@code recycle()}
     * is called.
     */
    public void recycle() {
        // do nothing
    }
    /**
     * Releases memory temporarily and allows this object to be used still.
     */
    public void release(Context context) {
        // do nothing
    }
    public abstract BaseItem copy();
    @Override
    public abstract void render(Canvas canvas, Paint paint, Context context);
    public float getDegree() {
        return degree;
    }

    public BaseStateFile getStateFile() {
        return null;
    }

    @ColorInt
    public int getColorToBeCompared() {
        return color;
    }
}